package dotaframework.game;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

import dota.entity.ArmedUnit;
import gameframework.base.ObservableValue;
import gameframework.game.CanvasDefaultImpl;
import gameframework.game.Game;
import gameframework.game.GameLevel;

public class DotaGameImpl implements Game, Observer {

	protected static final int NB_ROWS = 39;
	protected static final int NB_COLUMNS = 42;
	protected static final int SPRITE_SIZE = 16;
	public static final int MAX_NUMBER_OF_PLAYER = 4;
	//public static final int NUMBER_OF_LIVES = 1;

	protected CanvasDefaultImpl defaultCanvas = null;
	protected ObservableValue<Integer> experience[] = new ObservableValue[MAX_NUMBER_OF_PLAYER];
	protected ObservableValue<Integer> heroLevel[] = new ObservableValue[MAX_NUMBER_OF_PLAYER];
	protected ObservableValue<Integer> gold[] = new ObservableValue[MAX_NUMBER_OF_PLAYER];

	// initialized before each level
	protected ObservableValue<Boolean> endOfGame = null;

	protected Frame f;
	//private GameLevelDefaultImpl currentPlayedLevel = null;

	//protected int levelNumber;
	protected ArrayList<GameLevel> gameLevels;

	protected Label heroLvlText, xpText, goldText;
	protected Label information;
	protected Label informationValue;
	protected Label heroLvlValue, xpValue, goldValue;
	
	protected ArmedUnit hero1;

	public DotaGameImpl() {
		gameLevels = new ArrayList<GameLevel>();
		
		for (int i = 0; i < MAX_NUMBER_OF_PLAYER; ++i) {
			experience[i] = new ObservableValue<Integer>(10);
			heroLevel[i] = new ObservableValue<Integer>(0);
			gold[i] = new ObservableValue<Integer>(0);
		}
		heroLvlText = new Label("Hero level:");
		xpText = new Label("Experience:");
		goldText = new Label("Gold:");
		information = new Label("State:");
		informationValue = new Label("Playing");
		createGUI();
	}

	public void createGUI() {
		f = new Frame("Dota");
		f.dispose();

		createMenuBar();
		Container c = createStatusBar();
		Container c2 = createBuyFrame();

		defaultCanvas = new CanvasDefaultImpl();
		defaultCanvas.setSize(SPRITE_SIZE * NB_COLUMNS, SPRITE_SIZE * NB_ROWS);
		f.add(defaultCanvas);
		f.add(c, BorderLayout.SOUTH);
		f.add(c2, BorderLayout.EAST);
		f.pack();
		f.setVisible(true);

		f.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
	}

	protected void createMenuBar() {
		MenuBar menuBar = new MenuBar();
		Menu file = new Menu("file");
		MenuItem start = new MenuItem("new game");
		MenuItem save = new MenuItem("save");
		MenuItem restore = new MenuItem("load");
		MenuItem quit = new MenuItem("quit");
		Menu game = new Menu("game");
		MenuItem pause = new MenuItem("pause");
		MenuItem resume = new MenuItem("resume");
		menuBar.add(file);
		menuBar.add(game);
		f.setMenuBar(menuBar);

		start.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				start();
			}
		});
		save.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				save();
			}
		});
		restore.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				restore();
			}
		});
		quit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});
		pause.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				pause();
			}
		});
		resume.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				resume();
			}
		});

		file.add(start);
		file.add(save);
		file.add(restore);
		file.add(quit);
		game.add(pause);
		game.add(resume);
	}

	private Container createStatusBar() {
		JPanel c = new JPanel();
		GridLayout layout = new GridLayout(1,5);
		c.setLayout(layout);
		heroLvlValue = new Label(Integer.toString(heroLevel[0].getValue()));
		xpValue = new Label(Integer.toString(experience[0].getValue()));
		goldValue = new Label(Integer.toString(gold[0].getValue()));
		c.add(heroLvlText);
		c.add(heroLvlValue);
		c.add(xpText);
		c.add(xpValue);
		c.add(goldText);
		c.add(goldValue);
		c.add(information);
		c.add(informationValue);
		
		return c;
	}
	
	private Container createBuyFrame(){
		JPanel c = new JPanel();
		BoxLayout layout = new BoxLayout(c, BoxLayout.Y_AXIS);
		
		
		JLabel sw1 = new JLabel( new ImageIcon( "images/Sword1.gif"));
		JLabel infoTC = new JLabel("Buy sword (A)");
		JLabel damage1 = new JLabel("Damage : 15");
		JLabel cost1 = new JLabel("Cost : 200");
		JLabel sw2 = new JLabel(new ImageIcon( "images/Sword2.gif"));
		JLabel infoTB = new JLabel("Buy Magic sword (Z)");
		JLabel damage2 = new JLabel("Damage : 35");
		JLabel cost2 = new JLabel("Cost : 500");
		JLabel sw3 = new JLabel(new ImageIcon( "images/Sword3.gif"));
		JLabel infoTE = new JLabel("Buy death axe (E)");
		JLabel damage3 = new JLabel("Damage : 75");
		JLabel cost3 = new JLabel("Cost : 1500");


		c.setLayout(layout);
		c.add(sw1);
		c.add(Box.createRigidArea(new Dimension(30,10)));
		c.add(infoTC);
		c.add(damage1);
		c.add(cost1);
		
		
		c.add(Box.createRigidArea(new Dimension(0,30)));
		c.add(sw2);
		c.add(Box.createRigidArea(new Dimension(0,10)));
		c.add(infoTB);
		c.add(damage2);
		c.add(cost2);
		
		c.add(Box.createRigidArea(new Dimension(0,30)));
		c.add(sw3);
		c.add(Box.createRigidArea(new Dimension(0,10)));
		c.add(infoTE);
		c.add(damage3);
		c.add(cost3);
		
		return c;
	}

	public Canvas getCanvas() {
		return defaultCanvas;
	}

	public void start() {
		for (int i = 0; i < MAX_NUMBER_OF_PLAYER; ++i) {
			heroLevel[i].addObserver(this);
			experience[i].addObserver(this);
			gold[i].addObserver(this);
			heroLevel[i].setValue(1);
			gold[i].setValue(0);
			experience[i].setValue(0);
		}
		gameLevels.get(0).start();

	}

	public void restore() {
		System.out.println("restore(): Unimplemented operation");
	}

	public void save() {
		System.out.println("save(): Unimplemented operation");
	}

	public void pause() {
		System.out.println("pause(): Unimplemented operation");
		// currentPlayedLevel.suspend();
	}

	public void resume() {
		System.out.println("resume(): Unimplemented operation");
		// currentPlayedLevel.resume();
	}

	public ObservableValue<Integer>[] experience() {
		return experience;
	}
	
	public ObservableValue<Integer>[] heroLevel() {
		return heroLevel;
	}

	public ObservableValue<Integer>[] gold() {
		return gold;
	}

	public ObservableValue<Boolean> endOfGame() {
		return endOfGame;
	}

	public void setLevel(GameLevel level) {
		gameLevels.add(level);
	}

	public void update(Observable o, Object arg) {
		if (o == endOfGame) {
			if (endOfGame.getValue()) {
				informationValue.setText("You win");
			}
		} else {
			for (ObservableValue<Integer> lvlObservable : heroLevel) {
				if (o == lvlObservable) {
					int lives = ((ObservableValue<Integer>) o).getValue();
					heroLvlValue.setText(Integer.toString(lives));
				}
			}
			for (ObservableValue<Integer> expObservable : experience) {
				if (o == expObservable) {
					xpValue
							.setText(Integer
									.toString(((ObservableValue<Integer>) o)
											.getValue()));
					if ( ((ObservableValue<Integer>) o).getValue() >= 1000 )
					{
						//Level up
						((ObservableValue<Integer>) o).setValue(0);
						heroLevel[0].setValue(heroLevel[0].getValue()+1);
						hero1.levelUp();
					}
				}

				
			}
			
			for (ObservableValue<Integer> goldObservable : gold) {
				if (o == goldObservable) {
					goldValue
							.setText(Integer
									.toString(((ObservableValue<Integer>) o)
											.getValue()));
				}
			}
		}
	}

	@Override
	public ObservableValue<Integer>[] score() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ObservableValue<Integer>[] life() {
		// TODO Auto-generated method stub
		return null;
	}

	public void setHero(ArmedUnit hero) {
		hero1 = hero;
	}
}
